//
//  SQLiteDataSet.m
//  SQLiteDataSet

//  Created by ladaka31 ladaka on 13. 5. 31..
//  Copyright (c) 2013년 ladaka Inc. All rights reserved.

#import "SQLiteDataSet.h"

@implementation SQLiteDataSet
@synthesize dataFileName;
@synthesize isEOF;

- (id)init {
    self = [super init];
    if (self) {
        database = NULL;
        statement = NULL;
    }
    
    return self;
}

/**
 멤버변수 connected값을 리턴.
 */
- (BOOL)connected {
	return connected;
}

/**
 파라미터 value값이 YES이면 DB파일을 Open하고 NO일경우 DB파일을 Close한다. value값은 connected 멤버변수에 저장한다. \n
 DB파일이 존재하지 않으면 DBNotFound이름의 예외가 발생하고 DB파일을 오픈할 수 없으면 DBOpenFailed이름의 예외가 발생한다.\n
 @param value YES이면 DB파일 Open NO이면 DB파일 Close
 */
- (void)setConnected:(BOOL)value {
	if (value == YES) {
		NSFileManager *fileManager = [NSFileManager defaultManager];
		BOOL exist = [fileManager fileExistsAtPath:dataFileName];
		if (exist == NO) {
			NSException *exception = [NSException exceptionWithName:@"DBNotFound"
															 reason:@"Data file not found"  userInfo:nil];
			@throw exception;			
		}
                
		if (sqlite3_open([dataFileName UTF8String], &database) != SQLITE_OK) {
			sqlite3_close(database);
			NSException *exception = [NSException exceptionWithName:@"DBOpenFailed"
															 reason:@"Failed to Open database"  userInfo:nil];
			@throw exception;			
		}
	}
	else {
		if (statement != NULL) 
			sqlite3_finalize(statement);

		sqlite3_close(database);
	}

	connected = value;
}

/**
 파라미터 SQL로 데이터베이스에 쿼리를 질의한다. 쿼리 실행 에러가 발생하면 SQLError예외가 발생된다. \n
 SQL 결과집합이 있을경우 커서를 첫번째 레코드로 이동하고 isEOF False이다. SQL 결과 집합이 없을경우 프로퍼티 isEOF True이다.
 @param SQL 데이터베이스에 질의할 쿼리문장
 */
- (void)openSQL:(NSString *)sql {
    NSLog(@"%@", sql);
	isEOF = NO;

	// SQL 문장 초기화
	if (statement != NULL) {
		sqlite3_reset(statement);
		sqlite3_finalize(statement);
	}
	
	// SQL 문장 실행
	if (sqlite3_prepare_v2(database, [sql UTF8String], -1, &statement, NULL) != SQLITE_OK) {
		NSString *error = [NSString stringWithUTF8String:sqlite3_errmsg(database)];
		NSException *exception = [NSException exceptionWithName:@"SQLError"
														 reason:error  userInfo:nil];
		@throw exception;			
		
		return;
	}
	
	// 첫번째 레코드로 이동
	[self moveNext];
}

/**
 openSQL 함수에서 쿼리한 결과 집합에서 커서는 현재 레코드 다음으로 이동한다.
 */
- (void)moveNext {
	if (sqlite3_step(statement) == SQLITE_ROW)
		isEOF = NO;
	else
		isEOF = YES;
}

/**
 openSQL 함수에서 쿼리한 결과 집합의 파라미터 fieldName의 Column 인덱스를 리턴한다.\n
 fieldName이 쿼리 결과집합에 없는 경우 Column 인덱스가 -1이다.
 @param fieldName 필드명
 @return Column 인덱스
 */
- (int)getFieldIndexOf:(NSString *)fieldName {	
    for (int i =0; i <sqlite3_column_count(statement); i++)
    {
		NSString *sqliteColumnName = [NSString stringWithUTF8String:sqlite3_column_name(statement, i)];
		if ([fieldName isEqualToString:sqliteColumnName]) {
			return i;
		}
    }
	
    return -1;
}

/**
 openSQL 함수에서 쿼리한 결과 집합의 현재 커서애서 파라미터 fieldName으로 해당 필드 값을 String 타입으로 리턴한다.\n
 필드 값이 null인경우 빈문자열(@"")으로 리턴된다.
 fieldName이 쿼리 결과집합에 없는 경우 FieldError 예외 발생한다.
 @param fieldName 필드명
 @return String 타입의 필드 값
 */
- (NSString *)getFieldByValueAsString:(NSString *)fieldName {
	// 필드 갑 없을 경우 예외 발생
	int index = [self getFieldIndexOf:fieldName];
	if (index == -1) {
		NSString *error = [NSString stringWithFormat:@"fieldname '%@' not found", fieldName];
		NSException *exception = [NSException exceptionWithName:@"FieldError"
														 reason:error  userInfo:nil];
		@throw exception;			
	}
	
	// 필드 값 리턴
	const char *value = (char *)sqlite3_column_text(statement, index);
	if (value != nil) {
        NSString *string = [[NSString alloc] initWithUTF8String:value];
        if ([string isEqualToString:@"(null)"]) 
            return @"";

		return string;
	}
	else 
		return @"";
}

/**
 openSQL 함수에서 쿼리한 결과 집합의 현재 커서애서 파라미터 fieldName으로 해당 필드 값을 int 타입으로 리턴한다.\n
 fieldName이 쿼리 결과집합에 없는 경우 FieldError 예외 발생한다.
 @param fieldName 필드명
 @return int 탑입의 필드 값
 */
- (int)getFieldByValueAsInteger:(NSString *)fieldName {
	int index = [self getFieldIndexOf:fieldName];
	if (index == -1) {
		NSString *error = [NSString stringWithFormat:@"fieldname '%@' not found", fieldName];
		NSException *exception = [NSException exceptionWithName:@"FieldError"
														 reason:error  userInfo:nil];
		@throw exception;			
	}
		
	int value = sqlite3_column_int(statement, index);
	return value;
}

/**
 openSQL 함수에서 쿼리한 결과 집합의 현재 커서애서 파라미터 fieldName으로 해당 필드 값을 double 타입으로 리턴한다.\n
 fieldName이 쿼리 결과집합에 없는 경우 FieldError 예외 발생한다.
 @param fieldName 필드명
 @return double 탑입의 필드 값
 */
- (double)getFieldByValueAsDouble:(NSString *)fieldName {
	int index = [self getFieldIndexOf:fieldName];
	if (index == -1) {
		NSString *error = [NSString stringWithFormat:@"fieldname '%@' not found", fieldName];
		NSException *exception = [NSException exceptionWithName:@"FieldError"
														 reason:error  userInfo:nil];
		@throw exception;			
	}
	
	double value = sqlite3_column_double(statement, index);
	return value;
}

/**
 Insert, Update, Delete SQL문장을 실행한다. 쿼리문장에 오류가 있을 경우 execute error 예외가 발생한다.
 @param sql 쿼리문
 */
- (void)executeSQL:(NSString *)sql {    
	char *errorMsg;
	if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) {
		sqlite3_close(database);
		
		NSString *error = [NSString stringWithUTF8String:errorMsg];
		NSException *exception = [NSException exceptionWithName:@"execute error"
														 reason:error  userInfo:nil];
		@throw exception;			
	}
}

@end
